package panda.transaction.concurrency;

import java.util.HashMap;
import java.util.Map;

import panda.file.Block;

public class LockTable {
	private static final long MAX_TIME = 10000;

	private Map<Block, Integer> locks = new HashMap<Block, Integer>();

	public synchronized void sharedLock(Block block) {
		try {
			long startTime = System.currentTimeMillis();
			while (getLock(block) < 0 && !waitingTooLong(startTime))
				wait(MAX_TIME);
			if (getLock(block) < 0)
				throw new Error("can't get shared lock");
			int lock = getLock(block);
			locks.put(block, lock + 1);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private boolean waitingTooLong(long startTime) {
		return System.currentTimeMillis() - startTime > MAX_TIME;
	}

	private int getLock(Block block) {
		Integer ival = locks.get(block);
		if (ival == null) {
			return 0;
		} else {
			return ival.intValue();
		}
	}

	synchronized void exclusiveLock(Block block) {
		try {
			long timestamp = System.currentTimeMillis();
			while (getLock(block) > 1 && !waitingTooLong(timestamp))
				wait(MAX_TIME);
			if (getLock(block) > 1)
				throw new Error("can't get exlusive lock");
			locks.put(block, -1);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	synchronized void release(Block block) {
		int val = getLock(block);
		if (val > 1)
			locks.put(block, val - 1);
		else {
			locks.remove(block);
			notifyAll();
		}
	}
}
